home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / gnuplot / term / latex.trm < prev    next >
Text File  |  1993-09-15  |  20KB  |  709 lines

  1. /*
  2.  * $Id: latex.trm%v 3.50 1993/07/09 05:35:24 woo Exp $
  3.  *
  4.  */
  5.  
  6. /* GNUPLOT - latex.trm */
  7. /*
  8.  * Copyright (C) 1990 - 1993   
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software  is provided "as is" without express or implied warranty.
  21.  * 
  22.  * This file is included by ../term.c.
  23.  *
  24.  * This terminal driver supports:
  25.  *   LaTeX pictures (latex).
  26.  *   LaTeX pictures with emTeX specials (emtex). 
  27.  *
  28.  * AUTHORS
  29.  *   David Kotz, Russell Lang
  30.  *
  31.  * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
  32.  * 
  33.  */
  34.  
  35. /* modified to optimize use of \rule for long lines */
  36. /* TLDC: modified to have nice line types */
  37.  
  38. /* the following LATEX driver has been modified by 
  39.    Russell Lang, eln272v@monu1.cc.monash.oz from the
  40.    GnuTeX 1.3 driver by David Kotz, David.Kotz@Dartmouth.edu.
  41.    Since then it has been further extended by David Kotz.
  42.    EmTeX driver by Russell Lang. */
  43.  
  44. /*  9 Dec 1992  LATEX_put_text rewritten to handle \\ newlines
  45.                 Daniel S. Lewart (d-lewart@uiuc.edu) */
  46.  
  47. #define TINY_STEP 0.5    /* tiny steps for high quality lines */
  48.  
  49. #define LATEX_PTS_PER_INCH (72.27)
  50. #define DOTS_PER_INCH (300)    /* resolution of printer we expect to use */
  51. #define LATEX_UNIT (LATEX_PTS_PER_INCH/DOTS_PER_INCH) /* dot size in pt */
  52.  
  53. /* 5 inches wide by 3 inches high (default) */
  54. #define LATEX_XMAX (5*DOTS_PER_INCH)  /* (LATEX_PTS_PER_INCH/LATEX_UNIT*5.0) */
  55. #define LATEX_YMAX (3*DOTS_PER_INCH)  /* (LATEX_PTS_PER_INCH/LATEX_UNIT*3.0) */
  56.  
  57. #define LATEX_HTIC (5*DOTS_PER_INCH/72)        /* (5./LATEX_UNIT) */
  58. #define LATEX_VTIC (5*DOTS_PER_INCH/72)        /* (5./LATEX_UNIT) */
  59. #define LATEX_HCHAR (DOTS_PER_INCH*53/10/72)    /* (5.3/LATEX_UNIT) */
  60. #define LATEX_VCHAR (DOTS_PER_INCH*11/72)    /* (11./LATEX_UNIT) */
  61.  
  62. static int LATEX_posx;
  63. static int LATEX_posy;
  64. int LATEX_fontsize = 10;
  65. char LATEX_font[MAX_ID_LEN+1] = "cmr";
  66. static enum JUSTIFY latex_justify=LEFT;
  67. static int latex_angle=0;
  68.  
  69. /* Default line-drawing character */
  70. /* the definition of plotpoint varies with linetype */
  71. #define LATEX_DOT "\\usebox{\\plotpoint}"
  72. #define LATEX_TINY_DOT "\\rule{1pt}{1pt}" /* for dots plot style */
  73.  
  74. /* POINTS */
  75. #define LATEX_POINT_TYPES 12    /* we supply more point types */
  76. static char GPFAR * GPFAR LATEX_points[] = {
  77.     "\\raisebox{-.8pt}{\\makebox(0,0){$\\Diamond$}}",
  78.     "\\makebox(0,0){$+$}",
  79.     "\\raisebox{-.8pt}{\\makebox(0,0){$\\Box$}}",
  80.     "\\makebox(0,0){$\\times$}",
  81.     "\\makebox(0,0){$\\triangle$}",
  82.     "\\makebox(0,0){$\\star$}",
  83.     "\\circle{12}", "\\circle{18}", "\\circle{24}",
  84.     "\\circle*{12}", "\\circle*{18}", "\\circle*{24}"
  85. };
  86.  
  87. /* LINES */
  88. static float LATEX_size = 0;    /* current thick of line in points */
  89. static float LATEX_dotspace = 0; /* current dotspace of line in points */
  90. #define LATEX_LINE_TYPES 6    /* number of line types below */
  91. #define LATEX_THIN_LINE 0    /* the thinnest solid line type */
  92. static struct {
  93.     float size;            /* size of dot, or thick of line in points */
  94.     float dotspace;            /* inter-dot space in points; 0 for lines */
  95.   } GPFAR LATEX_lines[] = {
  96.       {0.4, 0.0},            /* thin solid line */
  97.       {0.4, 5.0},            /* thin dotted line */
  98.       {0.8, 0.0},            /* thick solid line */
  99.       {1.0, 5.0},            /* thick dotted line */
  100.       {1.2, 0.0},            /* Thick solid line */
  101.       {1.0, 10.0},            /* thick widely dotted line */
  102.   };
  103.  
  104. /* for drawing dotted and solid lines */
  105. static void LATEX_dot_line();
  106. static void LATEX_solid_line();
  107. static void LATEX_rule();
  108. static void LATEX_flushdot();
  109. #define LATEX_flushrule() LATEX_rule(2, 0.,0.,0.,0.) /* flush old rule */
  110. static TBOOLEAN LATEX_moved = TRUE;    /* pen is up after move */
  111. static float LATEX_dotsize;    /* size of LATEX_DOT in units */
  112. static TBOOLEAN LATEX_needsdot = FALSE;/* does dotted line need termination? */
  113.  
  114. #ifdef EMTEX
  115. TBOOLEAN emtex=FALSE; /* not currently using emtex */
  116. static void EMTEX_solid_line();
  117. #endif
  118.  
  119. /* ARROWS */
  120. /* the set of non-vertical/non-horizontal LaTeX vector slopes */
  121. /* except negatives - they are handled specially */
  122. static struct vslope {
  123.     int dx, dy;
  124. } GPFAR LATEX_slopes[] = {
  125.     {1,1}, {1,2}, {1,3}, {1,4},
  126.     {2,1}, {2,3},
  127.     {3,1}, {3,2}, {3,4},
  128.     {4,1}, {4,3},
  129.     {0,0}                    /* terminator */
  130. };
  131. static void best_latex_arrow(); /* figure out the best arrow */
  132.  
  133. LATEX_options()
  134. {
  135.     extern struct value *const_express();
  136.     extern double real();
  137.  
  138.     if (!END_OF_COMMAND) {
  139.         if (almost_equals(c_token,"c$ourier")) {
  140.             strcpy(LATEX_font,"cmtt");
  141.             c_token++;
  142.         }
  143.         else if (almost_equals(c_token,"r$oman")) {
  144.             strcpy(LATEX_font,"cmr");
  145.             c_token++;
  146.         }
  147.         else if (almost_equals(c_token,"d$efault")) {
  148.             strcpy(LATEX_font,"cmr");
  149.             LATEX_fontsize = 10;
  150.             c_token++;
  151.         }
  152.     }
  153.     
  154.     if (!END_OF_COMMAND) {
  155.         struct value a;
  156.         LATEX_fontsize = (int)real(const_express(&a));
  157.         term_tbl[term].v_char = (unsigned int)(LATEX_fontsize);
  158.         term_tbl[term].h_char = (unsigned int)(LATEX_fontsize);
  159.     }
  160.     sprintf(term_options,"%s %d point", LATEX_font ? "courier" : "roman",
  161.         LATEX_fontsize);
  162. }
  163.  
  164.  
  165. LATEX_init()
  166. {
  167. #ifdef EMTEX
  168.     emtex = FALSE;
  169. #endif
  170.     LATEX_posx = LATEX_posy = 0;
  171.     fprintf(outfile, "%% GNUPLOT: LaTeX picture\n");
  172.     fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
  173.     fprintf(outfile, 
  174.           "\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
  175.     LATEX_linetype(-1);
  176.     LATEX_size =0;
  177. }
  178.  
  179.  
  180. LATEX_scale(xs, ys)
  181.     double xs, ys;            /* scaling factors */
  182. {
  183.     register struct termentry *t = &term_tbl[term];
  184.  
  185.     /* we change the table for use in graphics.c and LATEX_graphics */
  186.     t->xmax = (unsigned int)(LATEX_XMAX * xs);
  187.     t->ymax = (unsigned int)(LATEX_YMAX * ys);
  188.  
  189.     return(TRUE);
  190. }
  191.  
  192. LATEX_graphics()
  193. {
  194.     register struct termentry *t = &term_tbl[term];
  195.  
  196.     fprintf(outfile, "\\begin{picture}(%d,%d)(0,0)\n", t->xmax, t->ymax);
  197.     fprintf(outfile, "\\font\\gnuplot=%s10 at %dpt\n", LATEX_font, LATEX_fontsize);
  198.     fprintf(outfile, "\\gnuplot\n");
  199. }
  200.  
  201.  
  202. LATEX_text()
  203. {
  204.     LATEX_flushrule();
  205.     LATEX_flushdot();
  206.     fprintf(outfile, "\\end{picture}\n");
  207.     LATEX_posx = LATEX_posy = 0; /* current position */
  208.     LATEX_moved = TRUE;    /* pen is up after move */
  209. }
  210.  
  211. LATEX_linetype(linetype)
  212.     int linetype;
  213. {
  214.     float size;
  215.  
  216.     if (linetype >= LATEX_LINE_TYPES)
  217.      linetype %= LATEX_LINE_TYPES;
  218.  
  219. #ifdef EMTEX
  220.     if (!emtex)
  221. #endif
  222.     LATEX_flushrule();
  223.     LATEX_flushdot();
  224.  
  225.     /* Find the new desired line thickness. */
  226.     /* negative linetypes (for axes) use a thin line */
  227.     /* only relevant for drawing axes/border in 3d */
  228.     size = (linetype >= 0 ? LATEX_lines[linetype].size 
  229.           : LATEX_lines[LATEX_THIN_LINE].size);
  230.  
  231.     /* If different from current size, redefine \plotpoint */
  232.     if (size != LATEX_size) {
  233.        fprintf(outfile, 
  234.              "\\sbox{\\plotpoint}{\\rule[%.3fpt]{%.3fpt}{%.3fpt}}%%\n",
  235.              -size/2, size, size);
  236. #ifdef EMTEX
  237.         if (emtex)         /* change line width */
  238.         fprintf(outfile, "\\special{em:linewidth %.1fpt}%%\n", size);
  239. #endif
  240.     }
  241.     
  242.     LATEX_size = size;
  243.     LATEX_dotsize = size / LATEX_UNIT;
  244.     LATEX_dotspace = (linetype >= 0) ? LATEX_lines[linetype].dotspace : 0;
  245.     LATEX_moved = TRUE;            /* reset */
  246. }
  247.  
  248. LATEX_move(x,y)
  249.     unsigned int x,y;
  250. {
  251.     LATEX_flushdot();
  252.  
  253.     LATEX_posx = x;
  254.     LATEX_posy = y;
  255.     LATEX_moved = TRUE;            /* reset */
  256. }
  257.  
  258.  
  259. LATEX_point(x,y, number)        /* version of line_and_point */
  260.     unsigned int x,y;
  261.     int number;                /* type of point */
  262. {
  263.     LATEX_move(x,y);
  264.     
  265.     /* Print the character defined by 'number'; number < 0 means 
  266.       to use a dot, otherwise one of the defined points. */
  267.     fprintf(outfile, "\\put(%d,%d){%s}\n", x, y, 
  268.           (number < 0 ? LATEX_TINY_DOT
  269.            : LATEX_points[number % LATEX_POINT_TYPES]));
  270. }
  271.  
  272.  
  273. LATEX_vector(ux,uy)
  274.     unsigned int ux,uy;
  275. {
  276.     if (LATEX_dotspace == 0.0) {
  277.        /* solid line */
  278. #ifdef EMTEX
  279.        if (emtex)
  280.         EMTEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
  281.        else
  282. #endif
  283.         LATEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
  284.     } else
  285.      /* dotted line */
  286.      LATEX_dot_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
  287.  
  288.     LATEX_posx = ux;
  289.     LATEX_posy = uy;
  290. }
  291.  
  292. static void
  293. LATEX_solid_line(x1,x2, y1,y2)
  294.     int x1,x2, y1,y2;
  295. {
  296.     float slope;
  297.     int inc;
  298.     float dx,dy,x,y;
  299.     float offset,length;
  300.     int code;                /* possibly combine with previous rule */
  301.  
  302.     /* we draw a solid line using the current line thickness (size) */
  303.     /* we do it with lots of \\rules */
  304.  
  305.     if (x1 == x2 && y1 == y2) { /* zero-length line - just a dot */
  306.        if (LATEX_moved) {
  307.           LATEX_flushrule();
  308.           /* plot a dot */
  309.           fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
  310.        }
  311.     } else {
  312.        code = (LATEX_moved ? 0 : 1); /* no combine after move */
  313.            LATEX_moved = FALSE;
  314.        if (x1 == x2)        /* vertical line - special case */
  315.         LATEX_rule(code, (double)x1, (double)y1,
  316.                LATEX_dotsize, (double)y2-y1);
  317.        else if (y1 == y2)    /* horizontal line - special case */
  318.         LATEX_rule(code, (double)x1, (double)y1, (double)x2-x1,
  319.                LATEX_dotsize);
  320.        else {
  321.           dx = (float)x2-x1;
  322.           dy = (float)y2-y1;
  323.           slope = dy/dx;
  324.           if (abs(slope) <= 1.0) {
  325.             /* longer than high */
  326.             x = min(abs(dx),(0.25+1.0/abs(slope))*LATEX_dotsize);
  327.             offset = sign(dy)*min(LATEX_dotsize,abs(dy));
  328.             dy = dy - offset;
  329.             length = x*LATEX_UNIT;
  330.             inc = (x == abs(dx) ? 1 : max(1,abs(dy)/TINY_STEP+0.5));
  331.             if (inc == 1) {
  332.               fprintf(outfile,"\\put(%u,%.2f){\\rule{%.3fpt}{%.3fpt}}\n",
  333.              (x2>=x1? x1 : x2), ((float)y1+y2-LATEX_dotsize)/2,
  334.              length, LATEX_dotsize*LATEX_UNIT);
  335.             } else {
  336.               dy = dy/inc;
  337.               dx = (dx-sign(dx)*x)/(inc-1);
  338. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
  339.                (dx>=0.0? (float)x1 : x1-x), 
  340.                (float)y1-(abs(dy)-offset)/2, 
  341.                dx, dy, inc, length, abs(dy)*LATEX_UNIT);
  342.             }
  343. /* done with one section, now smooth it */
  344.             x = x/2;
  345.             dx = sign(dx) * x;
  346.             dx = (float)x2 - x1 - dx;
  347.             dy = (float)y2 - y1;
  348. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
  349.              (dx>=0.0? (float)x1 : x1-x), (float)y1-LATEX_dotsize/2,
  350.              dx, dy, x*LATEX_UNIT, LATEX_dotsize*LATEX_UNIT);
  351.                 LATEX_moved = TRUE;
  352.           } else {
  353.             /* higher than long */
  354.             y = min(abs(dy),(0.25+abs(slope))*LATEX_dotsize);
  355.             offset = sign(dx)*min(LATEX_dotsize,abs(dx));
  356.             dx = dx - offset;
  357.             length = y*LATEX_UNIT;
  358.             inc = (y == abs(dy) ? 1 : max(1,abs(dx)/TINY_STEP+0.5));
  359.             if (inc == 1) {
  360.              fprintf(outfile,"\\put(%.2f,%u){\\rule{%.3fpt}{%.3fpt}}\n",
  361.              ((float)x1+x2-LATEX_dotsize)/2, (y2>=y1? y1 : y2),
  362.              LATEX_dotsize*LATEX_UNIT, length);
  363.             } else {
  364.               dx = dx/inc;
  365.               dy = (dy-sign(dy)*y)/(inc-1);
  366. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
  367.                (float)x1-(abs(dx)-offset)/2, 
  368.                (dy>=0? (float)y1 : y1-y), 
  369.                dx, dy, inc, abs(dx)*LATEX_UNIT, length);
  370.             }
  371. /* done with one section, now smooth it */
  372.             y = y/2;
  373.             dx = (float)x2 - x1;
  374.             dy = sign(dy) * y;
  375.             dy = (float)y2 - y1 - dy;
  376. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
  377.              (float)x1-LATEX_dotsize/2, (dy>=0.0? (float)y1 : y1-y),
  378.              dx, dy, LATEX_dotsize*LATEX_UNIT, y*LATEX_UNIT);
  379.                 LATEX_moved = TRUE;
  380.           }
  381.        }
  382.     }
  383. }
  384.  
  385. /* Draw a \rule. Width or height may be negative; we can correct.
  386.  * The rule is never output immediately. The previous rule is output
  387.  * as-is if code is 0, and the previous rule is
  388.  * combined with the current rule (if possible) if code is 1.
  389.  * The previous rule is output, and the new one ignored, if code is 2.
  390.  */
  391. static void
  392. LATEX_rule(code, x,y, width, height)
  393.     int code;                /* how do we treat this rule? */
  394.     double x, y;
  395.     double width;
  396.     double height;
  397. {  
  398.     static float lastx, lasty;
  399.     static float lastw, lasth;
  400.     static TBOOLEAN valid = FALSE; /* is 'last' data valid? */
  401.     TBOOLEAN combine = (code == 1);
  402.     TBOOLEAN flush = (code == 2);
  403.  
  404.     if (!flush)
  405.      if (width == 0 || height == 0)
  406.        return;            /* ignore this rule */
  407.  
  408.     if (valid && combine) {
  409.        /* try to combine new rule with old rule */
  410.        if ((int)lastx == (int)x && lastw == width) { /* vertical rule */
  411.           if (lasth * height >= 0) { /* same sign */
  412.              lasth += height;
  413.              return;
  414.           }
  415.        } else if ((int)lasty == (int)y && lasth == height){ /* horiz rule */
  416.           if (lastw * width >= 0) { /* same sign */
  417.              lastw += width;
  418.              return;
  419.           }
  420.        }
  421.        /* oh well, output last and remember the new one */
  422.     }
  423.  
  424.     if (valid) {
  425.        /* output the rule */
  426.        if (lastw < 0) {
  427.           lastx += lastw;
  428.           lastw = -lastw;
  429.        }
  430.        if (lasth < 0) {
  431.           lasty += lasth;
  432.           lasth = -lasth;
  433.        }
  434.  
  435.        /* if very small use canned dot */
  436.        if (lastw < LATEX_dotsize || lasth < LATEX_dotsize)
  437.         fprintf(outfile, "\\put(%.1f,%.1f){%s}\n",       
  438.                lastx, lasty, LATEX_DOT);
  439.        else
  440.         fprintf(outfile, "\\put(%.1f,%.1f){\\rule[%.3fpt]{%.3fpt}{%.3fpt}}\n",
  441.                lastx, lasty, -LATEX_dotsize*LATEX_UNIT/2,
  442.                lastw*LATEX_UNIT, lasth*LATEX_UNIT);
  443.     }
  444.     
  445.     if (flush) {
  446.        valid = FALSE;
  447.     } else {
  448.        lastx = x; lasty = y;
  449.        lastw = width; lasth = height;
  450.        valid = TRUE;
  451.     }
  452. }
  453.  
  454. static void
  455. LATEX_dot_line(x1,x2, y1,y2)
  456.     int x1,x2, y1,y2;
  457. {
  458.     static float LATEX_left;    /* fraction of space left after last dot */
  459. #ifndef AMIGA_AC_5
  460.     extern double sqrt();
  461. #endif
  462.     /* we draw a dotted line using the current dot spacing */
  463.  
  464.     if (LATEX_moved)
  465.      LATEX_left = 1.0;        /* reset after a move */
  466.  
  467.     /* zero-length line? */
  468.     if (x1 == x2 && y1 == y2) {
  469.        if (LATEX_moved)
  470.         /* plot a dot */
  471.         fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
  472.     } else {
  473.        float dotspace = LATEX_dotspace / LATEX_UNIT;
  474.        float x,y;            /* current position */
  475.        float xinc, yinc;    /* increments */
  476.        float slope;        /* slope of line */
  477.        float lastx = -1;    /* last x point plotted */
  478.        float lasty = -1;    /* last y point plotted */
  479.        int numdots = 0;    /* number of dots in this section */
  480.  
  481.        /* first, figure out increments for x and y */
  482.        if (x2 == x1) {
  483.           xinc = 0.0;
  484.           yinc = (y2-y1>0)?dotspace:-dotspace;
  485.        } else {
  486.           slope = ((float)y2-y1)/((float)x2-x1);
  487.           xinc = dotspace / sqrt(1 + slope*slope) * sign(x2-x1);
  488.           yinc = slope * xinc;
  489.        }
  490.        
  491.        /* now draw the dotted line */
  492.        /* we take into account where we last placed a dot */
  493.        for (x=x1 + xinc*(1-LATEX_left), y=y1 + yinc*(1-LATEX_left);
  494.            (x2-x)*xinc >= 0 && (y2-y)*yinc >= 0; /* same sign or zero */
  495.            lastx = x, x += xinc, 
  496.            lasty = y, y += yinc)
  497.         numdots++;
  498.        if (numdots == 1)
  499.         fprintf(outfile, "\\put(%.2f,%.2f){%s}\n",
  500.            lastx, lasty, LATEX_DOT);
  501.        else
  502.         fprintf(outfile, "\\multiput(%u,%u)(%.3f,%.3f){%u}{%s}\n",
  503.                x1, y1, xinc, yinc, numdots, LATEX_DOT);
  504.  
  505.        /* how much is left over, as a fraction of dotspace? */
  506.        if (xinc != 0.0)            /* xinc must be nonzero */
  507.         if (lastx >= 0)
  508.           LATEX_left = abs(x2 - lastx) / abs(xinc);
  509.         else
  510.           LATEX_left += abs(x2-x1) / abs(xinc);
  511.        else
  512.         if (lasty >= 0)
  513.           LATEX_left = abs(y2 - lasty) / abs(yinc);
  514.         else
  515.           LATEX_left += abs(y2-y1) / abs(yinc);
  516.     }
  517.  
  518.     LATEX_needsdot = (LATEX_left > 0);
  519.  
  520.     LATEX_moved = FALSE;
  521. }
  522.  
  523. static void
  524. LATEX_flushdot()
  525. {
  526.     if (LATEX_needsdot) 
  527.      fprintf(outfile, "\\put(%d,%d){%s}\n", 
  528.             LATEX_posx, LATEX_posy, LATEX_DOT);
  529.     LATEX_needsdot = FALSE;
  530. }
  531.  
  532. LATEX_arrow(sx,sy, ex,ey, head)
  533.     int sx,sy, ex,ey;
  534.     TBOOLEAN head;
  535. {
  536.     best_latex_arrow(sx,sy, ex,ey, 1, head);
  537.  
  538.     LATEX_posx = ex;
  539.     LATEX_posy = ey;
  540. }
  541.  
  542. static void best_latex_arrow(sx,sy, ex,ey, who, head)
  543.     int sx,sy, ex,ey;        /* start and end points */
  544.     int who;                /* 1=LATEX, 2=EEPIC */
  545.     TBOOLEAN head;
  546. {
  547.     int dx = ex - sx;
  548.     int dy = ey - sy;
  549.     float m;                /* slope of line */
  550.     float arrowslope;        /* slope of arrow */
  551.     float minerror = 0;        /* best-case error */
  552.     struct vslope *slope;    /* one of the slopes */
  553.     struct vslope *bestslope;    /* the slope with min error */
  554.  
  555.     /* We try to draw a real arrow (ie, \vector). If we can't get
  556.     * a slope that is close, we draw a bent arrow.
  557.     */
  558.  
  559.     if (dx == 0) {
  560.        /* vertical arrow */
  561.        fprintf(outfile, "\\put(%d,%d){\\%s(0,%d){%d}}\n",
  562.              sx, sy, head ? "vector":"line", 
  563.              sign(ey-sy), abs(ey-sy));
  564.     } else if (dy == 0) {
  565.        /* horizontal arrow */
  566.        fprintf(outfile, "\\put(%d,%d){\\%s(%d,0){%d}}\n",
  567.              sx, sy, head ? "vector":"line",
  568.              sign(ex-sx), abs(ex-sx));
  569.     } else {
  570.        /* Slanted arrow. We'll give it a try.
  571.         * we try to find the closest-slope arrowhead.
  572.         */
  573.        bestslope = NULL;
  574.        minerror = 0; /* to shut up turbo C */
  575.        m = abs((float)dy/dx); /* the slope we want */
  576.        for (slope = LATEX_slopes; slope->dx != 0.0; slope++) {
  577.           /* find the slope of the arrow */
  578.           arrowslope = (float) slope->dy / slope->dx;
  579.           if (bestslope == NULL || abs(m-arrowslope) < minerror) {
  580.              minerror = abs(m-arrowslope);
  581.              bestslope = slope;
  582.           }
  583.        }
  584.  
  585.        /* now we have the best slope arrow */
  586.        /* maybe it's exactly the right slope! */
  587.        if (minerror == 0.0)    /* unlikely but possible */
  588.         fprintf(outfile, "\\put(%d,%d){\\%s(%d,%d){%d}}\n",
  589.                sx, sy, head ? "vector" : "line",
  590.                bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy),
  591.                abs(ex-sx));
  592.        else {
  593.           /* we draw the line the usual way, with thin lines */
  594. #ifdef EMTEX
  595.           if (emtex) {
  596.              LATEX_linetype(LATEX_THIN_LINE);
  597.              EMTEX_solid_line(sx,ex,sy,ey);
  598.           } else 
  599. #endif
  600.             if (who == 1) {
  601.                LATEX_linetype(LATEX_THIN_LINE);
  602.                LATEX_solid_line(sx,ex,sy,ey);
  603.             }
  604. #ifdef EEPIC
  605.             else {
  606.                EEPIC_move(sx,sy);
  607.                EEPIC_vector(ex,ey);
  608.             }
  609. #endif /* EEPIC */
  610.           /* and then draw an arrowhead (a short vector) there */
  611.             if (head)
  612.                   fprintf(outfile, "\\put(%d,%d){\\vector(%d,%d){0}}\n",
  613.                 ex, ey, 
  614.                 bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy));
  615.        }
  616.     }
  617. }
  618.  
  619. LATEX_put_text(x, y, str)
  620.     int x,y;            /* reference point of string */
  621.     char str[];         /* the text */
  622. {
  623.     static char *justify[] = { "[l]", "", "[r]" };
  624.     int flag,i;
  625.  
  626.     /* ignore empty strings */
  627.     if (str[0] == '\0')
  628.         return(0);
  629.  
  630.     for (flag=FALSE,i=0; str[i] && !flag;)
  631.         flag = (str[i++] == '\\') && (str[i++] == '\\');
  632.  
  633.     fprintf(outfile, "\\put(%d,%d)", x, y);
  634.     if (flag)
  635.         fprintf(outfile, "{\\makebox(0,0)%s{\\shortstack{%s}}}\n",
  636.             justify[latex_justify], str);
  637.     else
  638.         fprintf(outfile, "{\\makebox(0,0)%s{%s}}\n",
  639.             justify[latex_justify], str);
  640. }
  641.  
  642. int LATEX_justify_text(mode)
  643.     enum JUSTIFY mode;
  644. {
  645.     latex_justify = mode;
  646.     return (TRUE);
  647. }
  648.  
  649. int LATEX_text_angle(angle)
  650.     int angle;
  651. {
  652.     /* we can't really write text vertically, but this will 
  653.       put the ylabel centred at the left of the plot, and
  654.       then we'll make a \shortstack */
  655.     latex_angle = angle;
  656.     return (TRUE);
  657. }
  658.  
  659. LATEX_reset()
  660. {
  661.     LATEX_posx = LATEX_posy = 0; /* current position */
  662.     LATEX_moved = TRUE;    /* pen is up after move */
  663. }
  664.  
  665.  
  666. #ifdef EMTEX
  667.  
  668. EMTEX_init()
  669. {
  670.     emtex=TRUE;
  671.     LATEX_posx = LATEX_posy = 0;
  672.     fprintf(outfile, "%% GNUPLOT: LaTeX picture with emtex specials\n");
  673.     fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
  674.     fprintf(outfile, 
  675.           "\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
  676.     LATEX_linetype(-1);
  677. }
  678.  
  679.  
  680. EMTEX_reset()
  681. {
  682.     emtex=FALSE;
  683.     LATEX_posx = LATEX_posy = 0;
  684. }
  685.  
  686.  
  687. EMTEX_text()
  688. {
  689.     fprintf(outfile, "\\end{picture}\n");
  690. }
  691.  
  692.  
  693. static void
  694. EMTEX_solid_line(x1,x2, y1,y2)
  695.     int x1,x2, y1,y2;
  696. {
  697.     /* emtex special solid line */
  698.     if (LATEX_moved)
  699.         fprintf(outfile, "\\put(%d,%d){\\special{em:moveto}}\n", x1, y1);
  700.     if ( (x1!=x2) || (y1!=y2) )
  701.         fprintf(outfile, "\\put(%d,%d){\\special{em:lineto}}\n", x2, y2);
  702.     LATEX_posx = x2;
  703.     LATEX_posy = y2;
  704.     LATEX_moved = FALSE;
  705. }
  706.  
  707.  
  708. #endif /* EMTEX */
  709.